package com.tang.module.system.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tang.common.constant.SafetyConstant;
import com.tang.common.exception.GlobalException;
import com.tang.common.exception.SecurityException;
import com.tang.module.system.entity.Role;
import com.tang.module.system.entity.User;
import com.tang.module.system.mapper.MenuMapper;
import com.tang.module.system.entity.Menu;
import com.tang.module.system.service.MenuService;
import com.tang.module.system.vo.MenuVo;
import com.tang.module.system.wrapper.MenuWrapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单表(Menu)表服务实现类
 *
 * @author tang
 * @since 2022-01-20 17:29:39
 */
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Resource
    private MenuMapper menuMapper;



    @Override
    public List<Menu> button(User user) {
        List<Menu> menuList = new ArrayList<>();
        List<String> roleName = user.getRoleList().parallelStream().map(Role::getRoleName).collect(Collectors.toList());
        //如果是超级管理员，就获取全部，否则就获取对应的按钮
        if (roleName.contains(SafetyConstant.SUPER_ADMIN)) {
            menuList = menuMapper.buttonAll();
        }else {
            menuList = menuMapper.buttonRole(user.getRoleList().parallelStream().map(Role::getId).collect(Collectors.toList()));
        }
        //开始组装成树形结构
        return buttonTree(menuList);
    }

    @Override
    public List<Menu> tree(String category) {
        List<Menu> menuList = menuMapper.selectList(Wrappers.<Menu>lambdaQuery()
                .eq(! "3".equals(category), Menu::getCategory,category)
                .eq(Menu::getStatus,1)
                .orderByAsc(Menu::getSort));
        return createTree(0L,menuList);
    }

    @Override
    public List<Menu> loginTree() {
        //获得当前用户
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //获得用户
        User user = (User) authentication.getPrincipal();
        //获得用户角色信息
        List<Role> roleList = user.getRoleList();
        if (roleList.size() == 0){
            throw new SecurityException("该用户无任何角色,请连接管理员获取权限");
        }
        //获得角色名称集合·
        List<String> roleName = roleList.parallelStream().map(Role::getRoleName).collect(Collectors.toList());
        //超级管理员可以获得全部菜单
        if (roleName.contains(SafetyConstant.SUPER_ADMIN)){
            return this.tree("1");
        }
        //获得角色ID集合
        List<Long> roleId = roleList.parallelStream().map(Role::getId).collect(Collectors.toList());
        return this.createTree(0L,this.menuMapper.getRoleMenuNotButton(roleId));
    }

    @Override
    public List<Menu> createTree(Long fid, List<Menu> menuList) {
        List<Menu> list = new ArrayList<>();
        for (Menu menu : menuList) {
            if (menu.getParentId().equals(fid)){
                list.add(menu);
                menu.setChildren(createTree(menu.getId(),menuList));
            }
        }
        return list;
    }

    public List<Menu> buttonTree(List<Menu> menuList){
        //父级
        List<Menu> menus = menuList.parallelStream().filter(menu -> menu.getCategory() == 1).collect(Collectors.toList());
        //按钮级
        List<Menu> menusButton = menuList.parallelStream().filter(menu -> menu.getCategory() == 2).collect(Collectors.toList());
        //开始拼接
        return menus.parallelStream().map(menu ->
            menu.setChildren(menusButton.stream().filter(menu1 -> menu.getId().equals(menu1.getParentId())).collect(Collectors.toList()))
            ).collect(Collectors.toList());
    }

    @Override
    public List<MenuVo> treeVo(Integer status) {
        // 1,获得的是生效的菜单,0获得的是全部菜单
        List<Menu> menuList = menuMapper.selectList(Wrappers.<Menu>lambdaQuery().eq(status == 1,Menu::getStatus,status).orderByAsc(Menu::getSort));
        List<MenuVo> menuVoList = menuList.parallelStream().map(menu -> MenuWrapper.build().wrapper(menu)).collect(Collectors.toList());
        return createTreeVo(0L,menuVoList);
    }

    @Override
    public List<MenuVo> createTreeVo(Long fid, List<MenuVo> menuList) {
        List<MenuVo> list = new ArrayList<>();
        for (MenuVo menu : menuList) {
            if (menu.getParentId().equals(fid)){
                list.add(menu);
                menu.setChildrenVo(createTreeVo(menu.getId(),menuList));
            }
        }
        return list;
    }

    @Override
    public List<Menu> parentMenuLevel(Integer level) {
        //只获取一层,直接获取顶级菜单即可
        if (level == 1){
            return menuMapper.selectList(Wrappers.<Menu>lambdaQuery().eq(Menu::getParentId, 0).eq(Menu::getStatus,1).orderByAsc(Menu::getSort));
        }
        //获取两层，就是获取全部“菜单”类型菜单,不包含按钮
        if (level == 2){
            List<Menu> menuList = menuMapper.selectList(Wrappers.<Menu>lambdaQuery().eq(Menu::getCategory, 1).eq(Menu::getStatus, 1).orderByAsc(Menu::getSort));
            return this.createTree(0L, menuList);
        }
        throw new GlobalException("菜单层数不正确");
    }

    @Override
    public String parentMenuCommaString(Integer category,Long parentId,Long id) {
        //如果当前就是顶级菜单直接返回0
        if (parentId == 0){
            return "0";
        }
        Set<String> path = new HashSet<>();
        //循环获取上级
        while (true){
            Menu menu = menuMapper.selectOne(Wrappers.<Menu>lambdaQuery().select(Menu::getId, Menu::getParentId,Menu::getCategory).
                    eq(Menu::getId, parentId));
            if (menu == null){
                break;
            }
            parentId = menu.getParentId();
            path.add(String.valueOf(menu.getId()));
        }
        return StringUtils.join(path, ",");
    }

    @Override
    public List<String> roleGetMenu(Long id) {
        List<Menu> roleMenu = menuMapper.getRoleMenu(Collections.singletonList(id));
        //转换为String泛型的ID集合
        return Convert.convert(new TypeReference<List<String>>() {},
                roleMenu.parallelStream().map(Menu::getId).collect(Collectors.toList()));
    }
}
